
#include <condition_variable>
#include <atomic>
#include <mutex>

class latch
{
    std::atomic<std::ptrdiff_t>     counter_;
    mutable std::condition_variable cv_;
    mutable std::mutex              mut_;

public:
    explicit latch(std::ptrdiff_t const def = 1) : counter_(def)
    {
    }

    void count_down()
    {
        counter_ -= 1;
        cv_.notify_all();
    }

    void wait(long const ms = 0) const
    {
        if (counter_.load(std::memory_order_relaxed) == 0)
            return;
        std::unique_lock<std::mutex> lock(mut_);

        if (ms > 0)
        {
            cv_.wait_for(lock, std::chrono::milliseconds(ms), [&] {
                return counter_.load(std::memory_order_relaxed) == 0;
            });
        }
        else
        {
            cv_.wait(lock, [&] {
                return counter_.load(std::memory_order_relaxed) == 0;
            });
        }
    }
};